package com.summer.socket.http;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class HttpDemoApplication {

    public static void main(String[] args) {
        // Netty 采用了`多 Reactor 多线程模型（也称为领导者/追随者模式）`，这种模型结合了单 Reactor 多线程和多 Reactor 多线程的优点。
        // Netty 主要有三种线程模型‌，分别是：
        // 单 Reactor 单线程：所有的I/O操作都在一个线程中完成。这种模型的优点是简单且不需要上下文切换，不存在线程安全问题，但缺点是单个线程处理所有任务，无法充分利用多核CPU，且在高并发情况下容易成为瓶颈‌，这种方式简单但不适合高并发场景。
        //   如：EventLoopGroup mainGroup = new NioEventLoopGroup(1); serverBootstrap.group(mainGroup);
        // 单 Reactor 多线程：I/O操作由一个Reactor负责，而业务处理则通过线程池进行。这种方式解决了单线程模型的性能问题，但仍然存在单个Reactor处理所有I/O操作的瓶颈‌。
        //   如：EventLoopGroup mainGroup = new NioEventLoopGroup(1); EventLoopGroup workerGroup = new NioEventLoopGroup(); serverBootstrap.group(mainGroup, workerGroup);
        // 多 Reactor 多线程(主从 Reactor 多线程模型)：这是Netty推荐使用的模型。它包含一个主Reactor和多个从Reactor，主Reactor负责处理连接请求，从Reactor负责具体的I/O操作。这种方式能够更好地利用多核CPU，提高系统的并发处理能力‌‌。
        //   如：EventLoopGroup mainGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); serverBootstrap.group(mainGroup, workerGroup);

        // 定义两个线程组用于（主/从）线程组模式
        EventLoopGroup mainGroup = new NioEventLoopGroup(); // 主线程组，叫 mainGroup 或 bossGroup 都可以，用于接受客户端的连接，但不做任何处理（像老板一样不做事）。
        EventLoopGroup workerGroup = new NioEventLoopGroup(); // 从线程组，叫 workerGroup 或 slaveGroup 都可以，用于处理主线程组交过来的客户端连接数据（像仆从一样具体去处理老板接受过来的任务）。

        // netty 服务器的创建，ServerBootstrap 是一个启动类，让我们轻松的引导启动 ServerChannel
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // 设置主从线程组，将两个线程组设置到 netty ，它会自动使用这两个线程组来完成对应工作，不需要额外的操作。
        serverBootstrap.group(mainGroup, workerGroup);
        // 设置通道类型（为 NIO 的双向通道），当服务端（server）与客户端（Client）建立连接后会有相应的通道，这个通道的类型需要在这个地方进项相应的设置。
        serverBootstrap.channel(NioServerSocketChannel.class);
        // 当建立连接后会，我们的从线程池会对相应的连接通道（Channel）做处理，这个处理会对我们的 Channel 有一个初始化器（每一个 Channel 都有）。那么初始化器里会有很多的通道处理器类，通道处理器类是针对每个 Channel 做不同的处理的（相当于拦截器，责任链模式）。
        // 设置一个 childHandler 会针对我们的从线程组做相应的操作。这里有很多的 netty 定义的通道处理器类，实现丰富的功能。也允许我们开发者去重写这些通道处理器类
        // 每一个 channel 由多个 handler 共同组成管道（pipeline），这些 Handler 有我们来提供，这些 handler 在netty得语境里叫通道处理器类，用于针对我们得 channel 来进项处理（实际上就是链模式 pipeline，channel 和数据被 handler 层层处理加工）。
        // 这里可以直接设置 handler ，也可以是上面提到的初始化器，而初始化器其实就是初始化这个管道（pipeline 责任链）的初始化过程
        serverBootstrap.childHandler(new HttpServerInitializer()); // 设置为 null 暂不做任何处理。子处理器，用于处理 workerGroup

        try {
            // 启动服务器，并且设置端口号，同时设置启动方式为同步
            ChannelFuture channelFuture = serverBootstrap.bind(8081).sync();    // 这里绑定需要时间，所以 sync 同步一下等待返回就可以获取到建立的对应 ChannelFuture
            // 获取 channelFuture 的通道，然后通过 channel 获取关闭的 Future 并同步等待。
            channelFuture.channel().closeFuture().sync();   // 通道何时关闭也不时确定的，所以这里获取通道的 closeFuture 然后同步等待。
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 在服务器停止后优雅地关闭主/从线程组
            mainGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}
